class Sieve < ActiveRecord::Base
  PREDICATE_HASH = {"<=" => "不超过", ">=" => "不低于"}

  has_and_belongs_to_many :combinations, :class_name => "Sieve", 
    :foreign_key => "parent_id", 
    :association_foreign_key => "child_id",
    :join_table => "combinations"

  def self.create_new_sieve(param_hash)
    sieve = Sieve.new(param_hash)
    equivalence = find_equivalence sieve
    return equivalence if equivalence
    return sieve unless sieve.valid? 
    sieve.save
    return sieve
  end
  
  def self.combine(ids)
    raise InvalidArgumentError.new(ids) unless ids.length > 1
    sieves = ids.map{|id| Sieve.find id}
    master_sieve = sieves.shift
    parent = master_sieve.clone
    master_sieve.combinations.each{|child| parent.combinations << child }
    sieves.each{|child| parent.combinations << child }
    
    equivalence = find_equivalence parent
    return equivalence if equivalence
    
    parent.save
    return parent
  end
  
  def self.find_equivalence(sieve)
    Sieve.find(:all).select{|s| sieve.equivalent? s}.first
  end
  
  def self.date_to_s(date)
    return "最近一期的报表" if date == "recent"
    "#{date}发布的报表"
  end

  def sieve
    report = (is_recent?) ? MorningStarReport.recent : MorningStarReport.find_by_date(date)
    result = do_sieve(report)
    combinations.each do |child|
      child_result_codes = child.sieve.map{|fund| fund.code}
      result.delete_if{|fund| !child_result_codes.include? fund.code}
    end
    return sort(result)
  end
  
  def predication
    raise InvalidArgumentError.new(predicate) unless PREDICATE_HASH.has_key? predicate
    "value.to_f #{predicate} #{target}"
  end
  
  def equivalent?(another)
    another.is_a? Sieve and to_s == another.to_s
  end
  
  def to_s
    result = "#{date_desc}：#{Fund.field_label field}#{PREDICATE_HASH[predicate]}#{target}"
    combinations.each do |child|
      result << " 并且 "
      result << child.to_s
    end
    return result
  end
  
  def validate
    begin 
      sieve
    rescue Exception => e
      errors.add_to_base e.message
    end
  end
  
  private
  def date_desc
    Sieve.date_to_s(date)
  end
  
  def is_recent?
    date == "recent"
  end
  
  def do_sieve(report)
    report.stock_funds.select do |fund|
      value = fund.get(field)
      !value.empty? && eval(predication)
    end    
  end
  
  def sort(funds)
    funds.sort! do |a, b|
      left, right = (predicate == ">=") ? [b, a] : [a, b]
      left.get(field).to_f <=> right.get(field).to_f
    end
  end
end

class InvalidArgumentError < Exception
end